/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import ts from '../../vendor/ohos-typescript';

export function extractCallExpressionParts(child: ts.Node): {
  nameConcent: ts.Node;
  openParenToken: ts.Node;
  syntaxList: ts.Node;
  closeParenToken: ts.Node
} {
  const children = child.getChildren();
  let nameConcent: ts.Node;
  let openParenToken: ts.Node;
  let syntaxList: ts.Node;
  let closeParenToken: ts.Node;
  const callExpr = ts.isCallExpression(child);
  const cdLength = children.length;
  if (callExpr) {
    // 情况 1: 没有 new 关键
    nameConcent = children[0];
    openParenToken = children[cdLength - 3];
    syntaxList = children[cdLength - 2];
    closeParenToken = children[cdLength - 1];
  } else {
    // 情况 2: 有 new 关键字
    nameConcent = children[1];
    openParenToken = children[cdLength - 3];
    syntaxList = children[cdLength - 2];
    closeParenToken = children[cdLength - 1];
  }
  return { nameConcent, openParenToken, syntaxList, closeParenToken };
}

export function isFunctionBoundary(node: ts.Node): boolean {
  return ts.isFunctionLike(node) ||
    ts.isSourceFile(node) ||
    ts.isClassStaticBlockDeclaration(node);
}

export function isElseIfClause(node: ts.Node): boolean {
  return ts.isIfStatement(node) &&
    ts.isIfStatement(node.parent) &&
    node.parent.elseStatement === node;
}

export function checkNewAndCallExpression(node: ts.NewExpression | ts.CallExpression): boolean {
    const callee = node.expression;
    // 跳过泛型检测 new Array<Foo>() 或 Array<Foo>()
    if (
        (ts.isNewExpression(node) || ts.isCallExpression(node)) &&
        node.typeArguments && // 检测泛型参数
        ts.isIdentifier(callee) &&
        callee.text === 'Array'
    ) {
        return false;
    };
    if (
        ts.isCallExpression(node) &&
        node.questionDotToken &&
        (ts.isIdentifier(callee) || ts.isPropertyAccessExpression(callee))
    ) {
        //跳过 Array?.(x, y);
        if (node.arguments.length > 1) {
            return false;
        };
    }
    if (ts.isParenthesizedExpression(callee)) {
        const innerExpression = callee.expression;
        if (ts.isIdentifier(innerExpression) && innerExpression.text === 'Array') {
            return true;
        };
    } else if (ts.isIdentifier(callee) && callee.text === 'Array') {
        return checkGlobalArray(node);
    }
    return false;
};

export function checkGlobalArray(node: ts.NewExpression | ts.CallExpression): boolean {
    const callee = node.expression;
    const isGlobalArray = !isInLocalScope(callee);
    if (isGlobalArray) {
        if (!node.arguments || node.arguments.length === 0) {
            if (ts.isArrowFunction(node) || ts.isFunctionDeclaration(node)) {
                return false;
            };
            return true;
        } else if (node.arguments.length === 1) {
            const arg = node.arguments[0];
            if ((ts.isSpreadElement(arg) && arg.getText().includes('...'))) {
                return true;
            }
        } else {
            return true;// Array(x, y, z) 或 new Array(x, y, z)，多个参数
        }
    }
    return false;
};

export function isInLocalScope(node: ts.Node): boolean {
    let current = node.parent;
    while (current) {
        if (ts.isNewExpression(current)) {
            if (current.expression.getText() === 'Array' && current.arguments === undefined) {
                return false;
            };
        };
        if (ts.isVariableDeclaration(current) && current.name === node) {
            return true;
        }
        if (ts.isFunctionDeclaration(current) || ts.isModuleDeclaration(current)) {
            break;
        }
        current = current.parent;
    }
    return false;
};

export function isParenthesized(node: ts.Node): boolean {
  let current = node.parent;
  while (current) {
    if (ts.isParenthesizedExpression(current)) {
      return true;
    }
    if (ts.isConditionalExpression(current) ||
        ts.isIfStatement(current) ||
        ts.isForStatement(current) ||
        ts.isWhileStatement(current) ||
        ts.isDoStatement(current)) {
      return false;
    }
    current = current.parent;
  }
  return false;
}

export function shouldReportAssertion(node: ts.AssertionExpression): boolean {
    const { expression, type } = node;
    // 检查对象字面量中的属性断言
    if (ts.isObjectLiteralExpression(expression)) {
        return expression.properties.some(prop => {
            if (ts.isPropertyAssignment(prop)) {
                const value = prop.initializer;
                return ts.isAsExpression(value) && shouldReportAssertion(value);
            }
            return false;
        });
    }
    // 处理基本类型断言
    if (type.kind === ts.SyntaxKind.StringKeyword ||
        type.kind === ts.SyntaxKind.NumberKeyword) {
        return false;
    }
    // 不需要报错的情况
    if (!ts.isLiteralTypeNode(type)) { return false };
    if (ts.isTypeReferenceNode(type)) { return false };
    // 处理模板字面量
    if (ts.isTemplateLiteral(expression)) {
        return false;
    }
    // 检查字面量类型断言
    if (ts.isLiteralTypeNode(type)) {
        if (ts.isStringLiteral(expression) && ts.isStringLiteral(type.literal)) {
            return expression.text === type.literal.text;
        }
        if (ts.isNumericLiteral(expression) && ts.isNumericLiteral(type.literal)) {
            return expression.text === type.literal.text;
        }
    }
    return false;
};
